/*
 * SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: MulanPSL-2.0
 */
#![allow(
    dead_code,
    mutable_transmutes,
    non_camel_case_types,
    non_snake_case,
    non_upper_case_globals,
    unused_assignments,
    unused_mut
)]

use crate::common::*;

extern "C" {
    fn free(_: *mut libc::c_void);
    fn strcmp(_: *const libc::c_char, _: *const libc::c_char) -> libc::c_int;
    fn strdup(_: *const libc::c_char) -> *mut libc::c_char;
    fn setlocale(__category: libc::c_int, __locale: *const libc::c_char) -> *mut libc::c_char;
    fn sudo_debug_printf2_v1(
        func: *const libc::c_char,
        file: *const libc::c_char,
        line: libc::c_int,
        level: libc::c_int,
        fmt: *const libc::c_char,
        _: ...
    );
    static mut sudoers_subsystem_ids: [libc::c_uint; 0];
}

// 多处定义，后期统一处理
pub const kernel: libc::c_uint = 9;
pub const tty: libc::c_uint = 8;
pub const ppid: libc::c_uint = 7;
pub const global: libc::c_uint = 6;
pub const digest_only: libc::c_uint = 5;
pub const all: libc::c_uint = 4;
pub const any: libc::c_uint = 3;
pub const always: libc::c_uint = 2;
pub const once: libc::c_uint = 1;
pub const never: libc::c_uint = 0;

// 多处定义，后期统一处理
#[derive(Copy, Clone)]
#[repr(C)]
pub struct list_member {
    pub entries: C2RustUnnamed,
    pub value: *mut libc::c_char,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct C2RustUnnamed {
    pub sle_next: *mut list_member,
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct list_members {
    pub slh_first: *mut list_member,
}

// 多处定义，后期统一处理
#[derive(Copy, Clone)]
#[repr(C)]
pub union sudo_defs_val {
    pub flag: libc::c_int,
    pub ival: libc::c_int,
    pub uival: libc::c_uint,
    pub tuple: libc::c_uint,
    pub str_0: *mut libc::c_char,
    pub mode: mode_t,
    pub tspec: timespec,
    pub list: list_members,
}
static mut current_locale: libc::c_int = 0 as libc::c_int;
static mut user_locale: *mut libc::c_char = 0 as *const libc::c_char as *mut libc::c_char;
static mut sudoers_locale: *mut libc::c_char = 0 as *const libc::c_char as *mut libc::c_char;
#[no_mangle]
pub unsafe fn sudoers_getlocale() -> libc::c_int {
    debug_decl!(SUDOERS_DEBUG_UTIL!());
    debug_return_int!(current_locale);
}
#[no_mangle]
pub fn sudoers_initlocale(
    mut ulocale: *const libc::c_char,
    mut slocale: *const libc::c_char,
) -> bool {
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if !ulocale.is_null() {
            free(user_locale as *mut libc::c_void);
            user_locale = strdup(ulocale);
            if user_locale.is_null() {
                debug_return_bool!(false);
            }
        }
        if !slocale.is_null() {
            free(sudoers_locale as *mut libc::c_void);
            sudoers_locale = strdup(slocale);
            if sudoers_locale.is_null() {
                debug_return_bool!(false);
            }
        }
        sudo_debug_printf!(
            SUDO_DEBUG_INFO,
            b"%s: user locale %s, sudoers locale %s\0" as *const u8 as *const libc::c_char,
            get_function_name!(),
            user_locale,
            sudoers_locale
        );
        debug_return_bool!(true);
    } //unsafe
}
/*
 * Set locale to user or sudoers value.
 * Returns true on success and false on failure,
 * If prevlocale is non-NULL it will be filled in with the
 * old SUDOERS_LOCALE_* value.
 */
#[no_mangle]
pub fn sudoers_setlocale(mut newlocale: libc::c_int, mut prevlocale: *mut libc::c_int) -> bool {
    let mut res: *mut libc::c_char = std::ptr::null_mut::<libc::c_char>();

    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        match newlocale {
            SUDOERS_LOCALE_USER => {
                if !prevlocale.is_null() {
                    *prevlocale = current_locale;
                }
                if current_locale != SUDOERS_LOCALE_USER {
                    current_locale = SUDOERS_LOCALE_USER;
                    sudo_debug_printf!(
                        SUDO_DEBUG_DEBUG,
                        b"%s: setting locale to %s (user)\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        if !user_locale.is_null() {
                            user_locale as *const libc::c_char
                        } else {
                            b"\0" as *const u8 as *const libc::c_char
                        }
                    );

                    res = setlocale(
                        LC_ALL,
                        if !user_locale.is_null() {
                            user_locale as *const libc::c_char
                        } else {
                            b"\0" as *const u8 as *const libc::c_char
                        },
                    );
                    if !res.is_null() && user_locale.is_null() {
                        user_locale =
                            setlocale(6 as libc::c_int, std::ptr::null_mut::<libc::c_char>());
                        if !user_locale.is_null() {
                            user_locale = strdup(user_locale);
                        }
                        if user_locale.is_null() {
                            res = std::ptr::null_mut::<libc::c_char>();
                        }
                    }
                }
            }
            SUDOERS_LOCALE_SUDOERS => {
                if !prevlocale.is_null() {
                    *prevlocale = current_locale;
                }
                if current_locale != SUDOERS_LOCALE_SUDOERS {
                    current_locale = SUDOERS_LOCALE_SUDOERS;

                    sudo_debug_printf!(
                        SUDO_DEBUG_DEBUG,
                        b"%s: setting locale to %s (sudoers)\0" as *const u8 as *const libc::c_char,
                        get_function_name!(),
                        if !sudoers_locale.is_null() {
                            sudoers_locale as *const libc::c_char
                        } else {
                            b"C\0" as *const u8 as *const libc::c_char
                        }
                    );

                    res = setlocale(
                        LC_ALL,
                        if !sudoers_locale.is_null() {
                            sudoers_locale as *const libc::c_char
                        } else {
                            b"C\0" as *const u8 as *const libc::c_char
                        },
                    );
                    if res.is_null()
                        && !sudoers_locale.is_null()
                        && strcmp(sudoers_locale, b"C\0" as *const u8 as *const libc::c_char)
                            != 0 as libc::c_int
                    {
                        free(sudoers_locale as *mut libc::c_void);
                        sudoers_locale = strdup(b"C\0" as *const u8 as *const libc::c_char);
                        if !sudoers_locale.is_null() {
                            res = setlocale(LC_ALL, b"C\0" as *const u8 as *const libc::c_char);
                        }
                    }

                    /*if res.is_null() && !sudoers_locale.is_null() {
                        if strcmp(sudoers_locale, b"C\0" as *const u8 as *const libc::c_char)
                            != 0 as libc::c_int
                        {
                            free(sudoers_locale as *mut libc::c_void);
                            sudoers_locale = strdup(b"C\0" as *const u8 as *const libc::c_char);
                            if !sudoers_locale.is_null() {
                                res = setlocale(LC_ALL, b"C\0" as *const u8 as *const libc::c_char);
                            }
                        }
                    }*/
                }
            }
            _ => {}
        }

        debug_return_bool!(res.is_null());
    } //unsafe
}

#[no_mangle]
pub fn sudoers_warn_setlocale(mut restore: bool, mut cookie: *mut libc::c_int) -> bool {
    unsafe {
        debug_decl!(SUDOERS_DEBUG_UTIL!());

        if restore {
            debug_return_bool!(sudoers_setlocale(
                *cookie,
                std::ptr::null_mut::<libc::c_int>()
            ));
        }
        debug_return_bool!(sudoers_setlocale(SUDOERS_LOCALE_USER, cookie));
    } //unsafe
}

/*
 * Callback for sudoers_locale sudoers setting.
 */
#[no_mangle]
pub unsafe fn sudoers_locale_callback(mut sd_un: *const sudo_defs_val) -> bool {
    debug_decl!(SUDOERS_DEBUG_UTIL!());

    /*if sudoers_initlocale(std::ptr::null::<libc::c_char>(), (*sd_un).str_0) {
        if !(setlocale(LC_ALL, (*sd_un).str_0).is_null()) {
            debug_return_bool!(true);
        }
    }*/
    if sudoers_initlocale(std::ptr::null::<libc::c_char>(), (*sd_un).str_0)
        && !(setlocale(LC_ALL, (*sd_un).str_0).is_null())
    {
        debug_return_bool!(true);
    }

    debug_return_bool!(false);
}
